package handler;

import com.serotonin.modbus4j.BatchRead;
import com.serotonin.modbus4j.BatchResults;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.code.DataType;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.locator.BaseLocator;
import com.serotonin.modbus4j.locator.StringLocator;
import utils.TCPUtils;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;

public class PlcHandler {
    public static Object[] getPLCData(ModbusMaster master, Integer slaveId, List<String> plcAddresses, List<String> plcDataTypes,
                                      List<String> columnLenList, List<String> defaultList, PreparedStatement statement)
            throws ModbusTransportException, ErrorResponseException, SQLException {

        Object[] objects = new Object[plcDataTypes.size()];
        BatchRead<Integer> batch = new BatchRead<Integer>();
        for (int i = 0; i < plcDataTypes.size(); i++) {

            if ("INT".equals(plcDataTypes.get(i))) {
                batch.addLocator(i, BaseLocator.holdingRegister(slaveId, Integer.parseInt(plcAddresses.get(i)), DataType.TWO_BYTE_INT_SIGNED));
            } else if ("UINT".equals(plcDataTypes.get(i))) {
                batch.addLocator(i, BaseLocator.holdingRegister(slaveId, Integer.parseInt(plcAddresses.get(i)), DataType.TWO_BYTE_INT_UNSIGNED));
            } else if ("REAL".equals(plcDataTypes.get(i))) {
                batch.addLocator(i, BaseLocator.holdingRegister(slaveId, Integer.parseInt(plcAddresses.get(i)), DataType.FOUR_BYTE_FLOAT_SWAPPED));
            } else if ("DINT".equals(plcDataTypes.get(i))) {
                batch.addLocator(i, BaseLocator.holdingRegister(slaveId, Integer.parseInt(plcAddresses.get(i)), DataType.FOUR_BYTE_INT_SIGNED_SWAPPED));
            } else if ("UDINT".equals(plcDataTypes.get(i))) {
                batch.addLocator(i, BaseLocator.holdingRegister(slaveId, Integer.parseInt(plcAddresses.get(i)), DataType.FOUR_BYTE_INT_UNSIGNED_SWAPPED));
            } else if ("BOOL".equals(plcDataTypes.get(i))) {
                batch.addLocator(i, BaseLocator.holdingRegisterBit(slaveId, Integer.parseInt(plcAddresses.get(i)), 1));
            } else if ("VERCHAR".equals(plcDataTypes.get(i))) {
                int length = Integer.parseInt(columnLenList.get(i));
                batch.addLocator(i, new StringLocator(slaveId, length, Integer.parseInt(plcAddresses.get(i)), DataType.VARCHAR, length / 2));
            } else if ("CHAR".equals(plcDataTypes.get(i))) {
                int length = Integer.parseInt(columnLenList.get(i));
                batch.addLocator(i, new StringLocator(slaveId, length, Integer.parseInt(plcAddresses.get(i)), DataType.CHAR, length / 2));
            } else {
                objects[i] = null;
            }
        }
        batch.setContiguousRequests(true);
        BatchResults<Integer> results = master.send(batch);
        for (int i = 0; i < plcDataTypes.size(); i++) {
            objects[i] = results.getValue(i);
            statement.setObject(i + 1, objects[i] == null ? defaultList.get(i) : objects[i]);
        }
        statement.addBatch();
        return objects;
    }

    public static Object[] getPLCAndArrayData(ModbusMaster master, Integer slaveId, List<String> plcAddresses, List<String> plcDataTypes, List<String> lengthColumnList) throws ModbusTransportException, ErrorResponseException {

        Object[] objects = new Object[plcDataTypes.size()];
        BatchRead<Integer> batch = new BatchRead<Integer>();
        for (int i = 0; i < plcDataTypes.size(); i++) {

            if ("INT".equals(plcDataTypes.get(i))) {
                batch.addLocator(i, BaseLocator.holdingRegister(slaveId, Integer.parseInt(plcAddresses.get(i)), DataType.TWO_BYTE_INT_SIGNED));
            } else if ("UINT".equals(plcDataTypes.get(i))) {
                batch.addLocator(i, BaseLocator.holdingRegister(slaveId, Integer.parseInt(plcAddresses.get(i)), DataType.TWO_BYTE_INT_UNSIGNED));
            } else if ("REAL".equals(plcDataTypes.get(i))) {
                batch.addLocator(i, BaseLocator.holdingRegister(slaveId, Integer.parseInt(plcAddresses.get(i)), DataType.FOUR_BYTE_FLOAT_SWAPPED));
            } else if ("DINT".equals(plcDataTypes.get(i))) {
                batch.addLocator(i, BaseLocator.holdingRegister(slaveId, Integer.parseInt(plcAddresses.get(i)), DataType.FOUR_BYTE_INT_SIGNED_SWAPPED));
            } else if ("UDINT".equals(plcDataTypes.get(i))) {
                batch.addLocator(i, BaseLocator.holdingRegister(slaveId, Integer.parseInt(plcAddresses.get(i)), DataType.FOUR_BYTE_INT_UNSIGNED_SWAPPED));
            } else if ("BOOL".equals(plcDataTypes.get(i))) {
                batch.addLocator(i, BaseLocator.holdingRegisterBit(slaveId, Integer.parseInt(plcAddresses.get(i)), 1));
            } else if ("VERCHAR".equals(plcDataTypes.get(i))) {
                int length = Integer.parseInt(lengthColumnList.get(i));
                batch.addLocator(i, new StringLocator(slaveId, length, Integer.parseInt(plcAddresses.get(i)), DataType.VARCHAR, length / 2));
            } else if ("CHAR".equals(plcDataTypes.get(i))) {
                int length = Integer.parseInt(lengthColumnList.get(i));
                batch.addLocator(i, new StringLocator(slaveId, length, Integer.parseInt(plcAddresses.get(i)), DataType.CHAR, length / 2));
            } else if ("FLOAT[ ]".equals(plcDataTypes.get(i))) {
                objects[i] = TCPUtils.getPLCCurveFloat(master, slaveId, Integer.parseInt(plcAddresses.get(i)), Integer.parseInt(lengthColumnList.get(i)));
            } else if ("LONG[ ]".equals(plcDataTypes.get(i))) {
                objects[i] = TCPUtils.getPLCCurve(master, slaveId, Integer.parseInt(plcAddresses.get(i)), Integer.parseInt(lengthColumnList.get(i)));
            } else if ("LONG[ ]".equals(plcDataTypes.get(i))) {
                objects[i] = TCPUtils.getPLCCurve(master, slaveId, Integer.parseInt(plcAddresses.get(i)), Integer.parseInt(lengthColumnList.get(i)));
            } else {
                objects[i] = null;
            }
        }
        batch.setContiguousRequests(false);
        BatchResults<Integer> results = master.send(batch);
        for (int i = 0; i < plcDataTypes.size(); i++) {
            if ("FLOAT[ ]".equals(plcDataTypes.get(i)) || "LONG[ ]".equals(plcDataTypes.get(i))) {
                continue;
            }
            objects[i] = results.getValue(i);
        }
        return objects;
    }
}
